﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CrossLayerCommunication.FluentValidation;
using CrossLayerCommunication;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.QualityTools.Testing.Fakes;

namespace UnitTest.FluentValidation
{
    [TestClass]
    public class TestFluentValidation
    {
        [TestMethod]        
        public void TestInitialization()
        {
            //arrange
            string value = "Testing";

            //act, assert
            Assert.AreEqual(value, value.TestingFluentValidation().ValidatedValue);
            Assert.AreEqual(FluentValidationTestHelper.ErrorMessage, value.TestingFluentValidation().ValidationMessage);
            Assert.IsTrue(value.TestingFluentValidation().ValidationWasSuccessful);
            Assert.IsTrue(value.TestingFluentValidation().WasLastValidationConditionMet);
        }

        [TestMethod]
        public void TestInvalidation()
        {
            //arrange
            StringBuilder value = new StringBuilder();

            //act
            var invalidatedFluentValidation = value.TestingFluentValidation().Invalidate();

            //assert
            Assert.AreEqual(value, invalidatedFluentValidation.ValidatedValue);
            Assert.AreEqual(FluentValidationTestHelper.ErrorMessage, invalidatedFluentValidation.ValidationMessage);
            Assert.IsFalse(invalidatedFluentValidation.ValidationWasSuccessful);
            Assert.IsTrue(invalidatedFluentValidation.WasLastValidationConditionMet);
        }

        [TestMethod]
        public void TestSetNewMessageIfValidationIsSuccessful()
        {
            //arrange
            Dictionary<int, string> value = new Dictionary<int, string>();
            IMessage changedMessage = MessageHelper.CreateOrGetMessage(-2);
 
            //act
            var changedMessageFluentValidation = value.TestingFluentValidation().SetNewMessage(changedMessage);

            //assert
            Assert.AreEqual(value, changedMessageFluentValidation.ValidatedValue);
            Assert.AreEqual(changedMessage, changedMessageFluentValidation.ValidationMessage);
            Assert.IsTrue(changedMessageFluentValidation.ValidationWasSuccessful);
            Assert.IsTrue(changedMessageFluentValidation.WasLastValidationConditionMet);
        }

        [TestMethod]
        public void TestSetNewMessageIfValidationIsNotSuccessful()
        {
            //arrange
            Dictionary<int, string> value = new Dictionary<int, string>();
            IMessage changedMessage = MessageHelper.CreateOrGetMessage(-2);

            //act
            var changedMessageFluentValidation = value.TestingFluentValidation().Invalidate().SetNewMessage(changedMessage);

            //assert
            Assert.AreEqual(value, changedMessageFluentValidation.ValidatedValue);
            Assert.AreEqual(FluentValidationTestHelper.ErrorMessage, changedMessageFluentValidation.ValidationMessage);
            Assert.IsFalse(changedMessageFluentValidation.ValidationWasSuccessful);
            Assert.IsTrue(changedMessageFluentValidation.WasLastValidationConditionMet);
        }

        [TestMethod]
        public void TestIfConditionNotMet()
        { 
            //arrange
            List<DateTime> value = new List<DateTime>();

            //act
            var conditionedFluentValidation = value.TestingFluentValidation()
                .If(item => item.Count > 10);

            //assert
            Assert.AreEqual(value, conditionedFluentValidation.ValidatedValue);
            Assert.AreEqual(FluentValidationTestHelper.ErrorMessage, conditionedFluentValidation.ValidationMessage);
            Assert.IsTrue(conditionedFluentValidation.ValidationWasSuccessful);
            Assert.IsFalse(conditionedFluentValidation.WasLastValidationConditionMet);
        }       

        [TestMethod]
        public void TestIfConditionIsMet()
        {
            //arrange
            DateTime dateTimeAdded = new DateTime(2011,1,1);
            List<DateTime> value = new List<DateTime>();
            value.Add(dateTimeAdded);

            //act
            var conditionedFluentValidation = value.TestingFluentValidation()
                .If(item => item.Count > 10)
                .If(item => item.Count == 1);

            //assert
            Assert.AreEqual(value, conditionedFluentValidation.ValidatedValue);
            Assert.AreEqual(FluentValidationTestHelper.ErrorMessage, conditionedFluentValidation.ValidationMessage);
            Assert.IsTrue(conditionedFluentValidation.ValidationWasSuccessful);
            Assert.IsTrue(conditionedFluentValidation.WasLastValidationConditionMet);
        }

        [TestMethod]
        public void TestIfConditionIsMetButInvalid()
        {
            //arrange
            DateTime dateTimeAdded = new DateTime(2011, 1, 1);
            List<DateTime> value = new List<DateTime>();
            value.Add(dateTimeAdded);

            //act
            var conditionedFluentValidation = 
                value.TestingFluentValidation()
                .Invalidate()                
                .If(item => item.Count == 1);

            //assert
            Assert.AreEqual(value, conditionedFluentValidation.ValidatedValue);
            Assert.AreEqual(FluentValidationTestHelper.ErrorMessage, conditionedFluentValidation.ValidationMessage);
            Assert.IsFalse(conditionedFluentValidation.ValidationWasSuccessful);
            Assert.IsTrue(conditionedFluentValidation.WasLastValidationConditionMet);
        }

        [TestMethod]
        public void TestPerformValidationInvalidationSuccessful()
        {
            //arrange
            FluentValidation<decimal> fluentValidation = new FluentValidation<decimal>(10, FluentValidationTestHelper.ErrorMessage, true, true);

            //act 
            var fluentValidationPerformed = fluentValidation.PerformValidation(fv => true);

            //assert
            Assert.IsFalse(fluentValidationPerformed.ValidationWasSuccessful);
        }

        [TestMethod]
        public void TestPerformValidationInvalidationUnSuccessfulValidationConditionNotMet()
        {
            //arrange
            FluentValidation<decimal> fluentValidation = new FluentValidation<decimal>(10, FluentValidationTestHelper.ErrorMessage, true, false);

            //act 
            var fluentValidationPerformed = fluentValidation.PerformValidation(fv => true);

            //assert
            Assert.IsTrue(fluentValidationPerformed.ValidationWasSuccessful);
        }

        [TestMethod]
        public void TestPerformValidationInvalidationUnSuccessfulValidationActionNotMet()
        {
            //arrange
            FluentValidation<decimal> fluentValidation = new FluentValidation<decimal>(10, FluentValidationTestHelper.ErrorMessage, true, true);

            //act 
            var fluentValidationPerformed = fluentValidation.PerformValidation(fv => false);

            //assert
            Assert.IsTrue(fluentValidationPerformed.ValidationWasSuccessful);
        }
                
        [TestMethod]
        public void TestPerformValidationInvalidationUnSuccessfulValidationPreviouslyNotMet()
        {            
            using (ShimsContext.Create())
            {
                //arrange
                FluentValidation<decimal> fluentValidation = new FluentValidation<decimal>(10, FluentValidationTestHelper.ErrorMessage, false, true);
                int numberOfCallsToInvalidate = 0;
                CrossLayerCommunication.FluentValidation.Fakes.ShimFluentValidationExtensions.InvalidateOf1IFluentValidationOfM0<decimal>(
                    fv =>
                    {
                        numberOfCallsToInvalidate = numberOfCallsToInvalidate + 1;
                        return fv;
                    });

                 //act 
                var fluentValidationPerformed = fluentValidation.PerformValidation(fv => true);                

                //assert
                Assert.AreEqual(0, numberOfCallsToInvalidate);
                Assert.IsFalse(fluentValidationPerformed.ValidationWasSuccessful);                
            }           
        }
    }
}
